package com.hulk.dryad.manage.limiter.expression;



import com.hulk.dryad.common.annotation.Limiter;
import lombok.NoArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author  hulk
 * 获取用户定义业务key
 */
@NoArgsConstructor
public class LimiterKeyExpressionResolver {

	private static final  ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

	private static final  ExpressionParser PARSER = new SpelExpressionParser();

    public String getKeyName(JoinPoint joinPoint, Limiter limit) {
        List<String> keyList = new ArrayList<>();
        Method method = getMethod(joinPoint);
		if (!ObjectUtils.isEmpty(limit.keys())) {{
			List<String> definitionKeys = getSpelDefinitionKey(limit.keys(), method, joinPoint.getArgs());
			keyList.addAll(definitionKeys);
		}}
        return StringUtils.collectionToDelimitedString(keyList,"-","","");
    }

    private Method getMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (method.getDeclaringClass().isInterface()) {
            try {
                method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(),
                        method.getParameterTypes());
            } catch (Exception e) {
				throw new RuntimeException(e);
            }
        }
        return method;
    }

    private List<String> getSpelDefinitionKey(String[] definitionKeys, Method method, Object[] parameterValues) {
		EvaluationContext context = new MethodBasedEvaluationContext(null, method, parameterValues, NAME_DISCOVERER);
    	List<String> definitionKeyList = new ArrayList<>(definitionKeys.length);
        for (String definitionKey : definitionKeys) {
			if (!StringUtils.isEmpty(definitionKey)) {
				Object objKey = PARSER.parseExpression(definitionKey).getValue(context);
				definitionKeyList.add(ObjectUtils.nullSafeToString(objKey));
            }
        }
        return definitionKeyList;
    }

}
